package com.example.demo.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.dao.DeptMapper;
import com.example.demo.dao.EmployeeMapper;
import com.example.demo.listener.EmpListener;
import com.example.demo.pojo.Dept;
import com.example.demo.pojo.Employee;
import com.example.demo.pojo.EmployeeDo;
import com.example.demo.pojo.Result;
import com.example.demo.service.DeptService;
import com.example.demo.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Description: EmpServiceImpl
 * </p>
 * @Author yangjiwang
 * @Date 2023/2/27
 */
@Service("empService")
public class EmpServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmpService {

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private DeptService deptService;


    @Override
    public Result<Employee> createOrUpdate(EmployeeDo emp) {
        //根据员工姓名和部门来判断是否存在
        //1.1 判断部门是否存在
        Dept dept = deptMapper.selectOne(new LambdaQueryWrapper<Dept>().eq(Dept::getDeptName, emp.getDeptName()));

        if (dept == null) {
            return Result.error("部门不存在，添加员工信息失败");
        }

        //1.2 判断员工信息是否存在
        Employee queryEmp = employeeMapper.selectOne(new LambdaQueryWrapper<Employee>()
                .eq(Employee::getEmpName, emp.getEmpName())
                .eq(Employee::getEmpDept, dept.getDeptId()));

        //1.3 存在员工信息，新建失败
        if (queryEmp != null) {
            return Result.error("员工信息已存在，新建失败");
        }

        //1.4 不存在，插入员工信息
        Employee insertEmp = Employee.builder()
                .empName(emp.getEmpName())
                .empEmail(emp.getEmpEmail())
                .empPhone(emp.getEmpPhone())
                .empDept(dept.getDeptId())
                .build();


        int flag = employeeMapper.insert(insertEmp);

        if (flag < 1) {
            return Result.error("新建员工信息失败");
        }
        return Result.ok("新建员工信息成功");
    }

    @Override
    public Result<List<EmployeeDo>> listEmpByDept(String deptName) {
        //判断请求参数是否为空
        if (StringUtils.isEmpty(deptName)) {
            return Result.error("部门名称为空，无法查询");
        }

        //查询
        Dept dept = deptMapper.selectOne(new LambdaQueryWrapper<Dept>()
                .eq(Dept::getDeptName, deptName));
        List<Employee> employeeList = employeeMapper.selectList(new LambdaQueryWrapper<Employee>()
                .eq(Employee::getEmpDept, dept.getDeptId()));
        List<EmployeeDo> resultList = employeeList.stream().map(
                item -> new EmployeeDo(item.getEmpId(), item.getEmpName(),
                        item.getEmpDept(), item.getEmpPhone(), item.getEmpEmail(),
                        dept.getDeptName())).collect(Collectors.toList());


        return Result.ok(resultList);
    }

    @Override
    public Result<Employee> parseExcel(MultipartFile file) {
        //需要插入数据库中的数据
        List<Employee> insertAndUpdateEmpList = new ArrayList<>();
        //Excel文件中的联系人信息
        List<EmployeeDo> excelEmpList = new ArrayList<>();

        try {
            //0. 判断文件格式
            if (StringUtils.isEmpty(file.getName())) {
                return Result.error("请上传文件");
            }
            String lastFileName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            if ( !("xlsx".equals(lastFileName) || "xls".equals(lastFileName) || "XLSX".equals(lastFileName) || "XLS".equals(lastFileName))) {
                return Result.error("请上传正确格式的文件");
            }

            //1. 读取 Excel 文件中的联系人信息
            EmpListener empListener = new EmpListener();
            EasyExcel.read(file.getInputStream(), EmployeeDo.class, empListener).sheet().doRead();
            excelEmpList = empListener.getEmployeeList();

        } catch (IOException e) {
            e.printStackTrace();
        }

        //2. 获取Excel中所有的部门
        Map<String, List<EmployeeDo>> excelEmpsGroupByDept = excelEmpList.stream().collect(Collectors.groupingBy(EmployeeDo::getDeptName));
        List<String> excelDepts = new ArrayList<>(excelEmpsGroupByDept.keySet());

        //3. 根据部门分类
        // 3.1 查询部门表中存在的部门 和不存在的部门
        //      存在的部门需要回填到部门Id
        List<Dept> inDepts = deptMapper.selectList(new LambdaQueryWrapper<Dept>().in(Dept::getDeptName, excelDepts));

        List<String> notInDepts = excelDepts.stream().filter(
                item -> inDepts.stream()
                        .map(Dept::getDeptName)
                        //不存在并且不为空的部门
                        .noneMatch(name -> Objects.equals(item, name) && StringUtils.isNotBlank(item)))
                .collect(Collectors.toList());

        // 3.2 不存在的部门  员工全部加入 insertEmpList
        //   3.2.1 新建部门，回填 部门Id
        List<Dept> insertDepts = notInDepts.stream().map(dept -> {
            return new Dept(null, dept, null, null);
        }).collect(Collectors.toList());
        deptService.saveBatch(insertDepts);
        //回填主键
        for (Dept dept : insertDepts) {
            List<EmployeeDo> dos = excelEmpsGroupByDept.get(dept.getDeptName());
            dos.forEach(item -> {
                item.setEmpDept(dept.getDeptId());
                //   3.2.2 员工信息全部加入insertEmpList
                insertAndUpdateEmpList.add(new Employee(null, item.getEmpName(),
                        item.getEmpDept(), item.getEmpPhone(),
                        item.getEmpEmail(), null, null));
            });
        }

        // 3.3 存在的部门中，判断员工信息是否存在
        //回填存在部门的员工的部门 id
        List<Employee> updateEmp = new ArrayList<>();
        for (Dept dept : inDepts) {
            List<EmployeeDo> dos = excelEmpsGroupByDept.get(dept.getDeptName());
            dos.forEach(item -> item.setEmpDept(dept.getDeptId()));
            //将 员工集合中 员工的名字提取为一个集合
            List<String> empNameList = dos.stream().map(EmployeeDo::getEmpName).collect(Collectors.toList());

            //存在的员工信息
            List<Employee> inEmp = employeeMapper.selectList(new LambdaQueryWrapper<Employee>()
                    .in(Employee::getEmpName, empNameList)
                    .eq(Employee::getEmpDept, dept.getDeptId()));

            for (Employee e : inEmp) {
                dos.forEach(d -> {
                    //更新相应人员的 联系电话
                    if (e.getEmpName().equals(d.getEmpName()) && !e.getEmpPhone().equals(d.getEmpPhone())) {
                        e.setEmpPhone(d.getEmpPhone());
                        updateEmp.add(e);
                    }
                });
            }

            //不存在的员工信息  加入 insertEmpList
            List<EmployeeDo> notInEmp = dos.stream().filter(
                    item -> inEmp.stream()
                            .map(Employee::getEmpName)
                            .noneMatch(name -> Objects.equals(name, item.getEmpName()) && StringUtils.isNotBlank(item.getEmpName()))
            ).collect(Collectors.toList());
            notInEmp.forEach(item -> {
                insertAndUpdateEmpList.add(new Employee(null, item.getEmpName(), item.getEmpDept(), item.getEmpPhone(),
                        item.getEmpEmail(), null, null));
            });
        }
        //   3.3.1 员工存在，（需要回填员工的Id）
        insertAndUpdateEmpList.addAll(updateEmp);

        //4. 批量插入或更新
        boolean flag = this.saveOrUpdateBatch(insertAndUpdateEmpList);
        if (flag) {
            return Result.ok("操作成功");
        } else {
            return Result.error("操作失败");
        }
    }

}
